/**
 * copyright (c) 2017-2021 Company
 * http://www.xxxxgame.cn/
 * 
 * UI管理器
 * z
 * 2019-02-28
 */

import { Asset, AssetManager, Node, Prefab, assetManager, find, instantiate, resources } from "cc";
import { MonoUIPanel } from "../../../../project-base/src/scripts/MonoUIPanel";



export class UIManager {

    /** 层级枚举 */
    public static EZIndex = {
        // 默认面板
        NORMAL: 100,
        // 挂件
        WIDGET: 5000,
        // 一级弹窗
        WINDOW: 10000,
        // 二级弹窗
        DIALOG: 15000,
        // 顶层提示
        TIP: 32767 - 1000,
        // 超顶层UI
        MAX: 32767 - 100
    };

    /** 事件 */
    public static EEventName = {
        OPEN_UI: 'OPEN_UI',
        CLOSE_UI: 'CLOSE_UI',
        CLOSE_UI_ALL: 'CLOSE_UI_ALL',
    };

    /** 过渡动画信息 */
    public static transitionInfo = null;

    // UI单例对象(私有化)
    private static instances = {};
    // 资源缓存
    public static assets = {};
    // 队列
    private static queue = [];
    // 当前显示的uiName
    private static queueUiName: string = null;

    /** 正在打开的面板 */
    private static opening = {};

    public static init() {
        // gg.systemEvent.on(UIManager.EEventName.CLOSE_UI_ALL, this.closeAll, this);
    }

    /** 关闭所有UI */
    public static closeAll() {
        for (const uiName in UIManager.instances) {
            UIManager.close(uiName);
        }
    }

    /**
     * 注册UI对象
     * @param uiNode 节点对象
     * @param uiName 节点名称
     */
    public static registerUI(uiNode: Node, uiName: string = undefined) {
        uiName = uiName || uiNode.name;
        UIManager.instances[uiName] = uiNode;
    }

    /**
     * 打开一个UI
     * @param uiName UI名称
     * @param callback 回调函数
     */
    public static async open(uiName: string, callback?: Function) {
        if (!uiName || uiName === '') { return; }

        const uiPath = uiName;
        const arr = uiName.split('/');
        uiName = arr[arr.length - 1];
        if (UIManager.opening[uiPath]) { return; }
        UIManager.opening[uiPath] = !0;
        try {
            // if (uiName !== 'GGLoadingMaskPanel' && uiName !== 'Loading/GGLoadingMaskPanel') {await UIManager.open('Loading/GGLoadingMaskPanel');}
            // 已有节点，重新显示
            let node: Node = UIManager.instances[uiName];
            if (node && node.getComponent && (node as any)._components) {
                node.active = true;
                UIManager.reshow(node, uiName);
                UIManager.opening[uiPath] = undefined;
                if (uiName !== 'GGLoadingMaskPanel') { UIManager.close('GGLoadingMaskPanel'); }
                gg.systemEvent.emit(UIManager.EEventName.OPEN_UI, { uiName, uiPath, node });
                callback && callback(undefined, node);
                return node;
            }

            // 新建节点
            const asset: any = UIManager.assets[uiName] || await UIManager.loadRes(`${uiPath}`, Prefab);
            UIManager.assets[uiName] = asset;
            node = instantiate(asset);
            UIManager.reshow(node, uiName);
            UIManager.instances[uiName] = node;
            UIManager.opening[uiPath] = undefined;
            if (uiName !== 'GGLoadingMaskPanel') { UIManager.close('GGLoadingMaskPanel'); }
            gg.systemEvent.emit(UIManager.EEventName.OPEN_UI, { uiName, uiPath, node });
            callback && callback(undefined, node);
            return node;
        } catch (error) {
            UIManager.opening[uiPath] = undefined;
            if (uiName !== 'GGLoadingMaskPanel') { UIManager.close('GGLoadingMaskPanel'); }
            callback ? callback(error) : console.error(error);
        }
    }

    /**
     * 打开一个UI，带过渡动画
     * @param uiName UI面板名称
     * @param transitionInfo 过渡动画参数
     */
    public static async openTrans(uiName: string, transitionInfo?: { transType: string, duration?: number, callback?: Function }) {
        const transUIName = `Loading/FLoading${transitionInfo.transType}Panel`;
        transitionInfo['uiName'] = uiName;
        UIManager.transitionInfo = transitionInfo;
        // 打开过渡动画面板
        await UIManager.open(transUIName);
    }

    /**
     * 关闭一个UI
     * @param uiName UI名称 | UI节点对象
     * @param callback 回调函数
     */
    public static close(uiName: string | Node, isDestroy: boolean = false) {
        if (!uiName) { return; }
        let node: Node;

        // 获取节点
        if (typeof uiName === 'string') {
            const arr = uiName.split('/');
            uiName = arr[arr.length - 1];
            node = UIManager.instances[uiName];
        } else {
            node = uiName;
            uiName = node.name;
        }

        if (!node) { return null; }

        // 关闭节点
        node.active = !1;
        node.parent = null;
        if (isDestroy) {
            UIManager.instances[uiName] = undefined;
            node.destroy();
        }
        gg.systemEvent.emit(UIManager.EEventName.CLOSE_UI, { uiName });
        return isDestroy ? null : node;
    }

    /**
     * 打开一个UI，并添加到队列
     * @param uiName UI名称
     * @param callback 回调函数
     */
    public static async openOnQueue(uiName: string, callback?: Function) {
        if (UIManager.queueUiName) { return UIManager.queue.push({ uiName, callback }); }

        UIManager.queueUiName = uiName;
        return await UIManager.open(uiName, callback);
    }

    /**
     * 关闭一个UI，并从队列移除
     * @param uiName UI名称 | UI节点对象
     * @param callback 回调函数
     */
    public static async closeOnQueue(uiName: string | Node, isDestroy: boolean = false) {
        UIManager.close(uiName, isDestroy);
        UIManager.queueUiName = null;

        const uiInfo = UIManager.queue.splice(0, 1)[0];
        if (uiInfo) {
            UIManager.queueUiName = uiInfo.uiName;
            await UIManager.open(uiInfo.uiName, uiInfo.callback);
        }
    }

    /**
     * 加载动态资源
     * @param path 资源路径
     */
    static loadBundle(path: string): Promise<Asset> {
        const bundleInfo = UIManager.getBundleName(path),
            bundle = assetManager.getBundle(bundleInfo.bundleName);
        console.log("===> loadBundle ", bundleInfo, bundle);
        if (bundle) {
            const panelPath = bundleInfo.assetPath;
            return new Promise((resolve, reject) => {
                bundle.load(panelPath, (error, asset) => {
                    if (error) { return reject(error); }
                    resolve(asset);
                });
            });
        }

        return new Promise((resolve, reject) => {
            // console.log('========', path, bundleInfo);
            const loadBundleCallback = (err, bundle: AssetManager.Bundle) => {
                if (err) { return reject(err); }

                bundle.load(bundleInfo.assetPath, (error, asset) => {
                    if (error) { return reject(error); }
                    resolve(asset);
                });
            };

            assetManager.loadBundle(bundleInfo.bundleName, loadBundleCallback);
        });
    }

    /**
     * 获取资源所在的bundle信息
     * @param path 资源路径
     */
    private static getBundleName(path: string) {
        let bundleName = '', assetPath = path;

        if (path.indexOf(':') !== -1) {
            const info = path.split(':');
            bundleName = info[0];
            assetPath = info[1];
        } else {
            let arr = path.split('/');
            if (arr[0] == 'ui') {
                bundleName = arr[1];
                assetPath = path.replace(`ui/${arr[1]}/`, '');
            } else {
                bundleName = arr[0];
                assetPath = path.replace(`${arr[1]}/`, '');
            }
        }

        return { bundleName, assetPath };
    }

    /** 获取平台对应的bundle名称 */
    static getPlatformBundleName() {
        let res = null;

        switch (gg.platform) {
            case gg.EPlatformType.QUICK_GAME_OPPO:
                res = 'mini_game_oppo';
                break;
            case gg.EPlatformType.QUICK_GAME_VIVO:
                res = 'mini_game_vivo';
                break;
            case gg.EPlatformType.MINI_GAME_QQ:
                res = 'mini_game_qq';
                break;
            case gg.EPlatformType.MINI_GAME_TT:
                res = 'mini_game_tt';
                break;
            case gg.EPlatformType.MINI_GAME_WX:
                res = 'mini_game_wx';
                break;

            default:
                break;
        }

        return res;
    }

    /**
     * 加载动态资源
     * @param path 资源路径
     * @param assetType 资源类型
     */
    static loadRes(path: string, assetType: typeof Asset): Promise<Asset> {
        return new Promise(async (resolve, reject) => {
            // 兼容子游戏
            if ((window as any).subGameBundle) {
                path = path.replace(':', '/');
                return (window as any).subGameBundle.load(path, assetType, async (err, res) => {
                    if (err) { return reject(err); }
                    return resolve(res);
                });
            }

            // 兼容bundle加载模式
            if (!resources) {
                try {
                    return resolve(await UIManager.loadBundle(path));
                } catch (error) {
                    return reject(error);
                }
            }

            // 兼容2.4版本引擎之前的游戏
            resources.load(path, assetType, async (err, res) => {
                if (err) {
                    try {
                        return resolve(await UIManager.loadBundle(path));
                    } catch (error) {
                        return reject(error);
                    }
                }

                return resolve(res);
            });
        });
    }

    /**
     * 加载Panel资源
     * @param uiName Panel资源路径
     * @param assetType 资源类型
     */
    static async loadResPanel(uiName: string, assetType: typeof Asset = Prefab): Promise<Asset> {
        const uiPath = uiName;
        const arr = uiName.split('/');
        uiName = arr[arr.length - 1];

        if (UIManager.assets[uiName]) { return UIManager.assets[uiName]; }
        UIManager.assets[uiName] = await UIManager.loadRes(`${uiPath}`, assetType);

        return UIManager.assets[uiName];
    }

    /**
     * 预加载Panel并创建
     * @param uiName Panel资源路径
     * @returns 
     */
    static async preloadPanel(uiName: string): Promise<Node> {
        let node: Node = UIManager.getUI(uiName);
        if (node) { return node; }

        const asset: any = await UIManager.loadResPanel(uiName);
        node = instantiate(asset);
        UIManager.instances[uiName] = node;

        return node;
    }

    /** 重置节点层级和父节点 */
    private static reshow(node: Node, uiName: string) {
        const names = uiName.replace(":", "/").split('/');
        uiName = names[names.length - 1];
        const com: MonoUIPanel = node.getComponent(uiName) as any;
        let parent: Node;
        if (com && com.parentUIName && com.parentUIName.trim() !== '') {
            parent = UIManager.instances[com.parentUIName.trim()];
        }
        try {
            parent = parent || find('Canvas');
            node.parent = parent;
            // node.zIndex = Number(com.zIndex) || 0;
            node['uiPanel'] = com;
        } catch (e) { console.error(e) }

    }

    /**
     * 获取UI节点对象
     *
     * @static
     * @param {string} uiName UI名称
     * @returns
     * @memberof UIManager
     */
    public static getUI(uiName: string): Node {
        return UIManager.instances[uiName];
    }

    /**
     * 查找节点（该节点所在的UIPanel必须已open）
     * @param nodePath 节点路径，格式(uiName/xxx/xxx/nodeName)
     * @returns 
     */
    public static findNode(nodePath: string): Node {
        let panelName;
        if (nodePath.indexOf(':') !== -1) {
            const info = nodePath.split(':');
            panelName = info[0];
            nodePath = info[1];
        }

        const panel = UIManager.getUI(panelName);
        if (!panel || !panel.active || !panel.parent) { return; }

        return find(nodePath, panel);
    }
}

UIManager.init();
try { (window as any).UIManager = UIManager; } catch (error) { }